"use client"; import * as React from "react"; import { Loader2, Users, Building2, AlertCircle } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { Badge } from "@/components/ui/badge"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Label } from "@/components/ui/label"; import { Separator } from "@/components/ui/separator"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { DepartmentNode } from "@/lib/users/knox-service"; import { getDepartmentDomainAssignmentsByDepartments, type UserDomain } from "@/lib/users/department-domain/service"; import { DOMAIN_OPTIONS, getDomainLabel } from "./domain-constants"; interface ExistingAssignment { id: number; companyCode: string; departmentCode: string; departmentName: string; assignedDomain: string; description?: string | null; createdAt: Date; updatedAt: Date; } interface DepartmentDomainAssignmentDialogProps { open: boolean; onOpenChange: (open: boolean) => void; selectedDepartments: string[]; departments: DepartmentNode[]; companyInfo: { code: string; name: string }; onAssign: (assignments: { departmentCodes: string[]; domain: string; description?: string; }) => Promise; isLoading?: boolean; } export function DepartmentDomainAssignmentDialog({ open, onOpenChange, selectedDepartments, departments, companyInfo, onAssign, isLoading = false, }: DepartmentDomainAssignmentDialogProps) { const [selectedDomain, setSelectedDomain] = React.useState(""); const [description, setDescription] = React.useState(""); const [isSubmitting, setIsSubmitting] = React.useState(false); const [existingAssignments, setExistingAssignments] = React.useState([]); const [isLoadingAssignments, setIsLoadingAssignments] = React.useState(false); // 선택된 부서들의 정보 가져오기 const getSelectedDepartmentInfo = React.useCallback(() => { const findDepartment = (nodes: DepartmentNode[], code: string): DepartmentNode | null => { for (const node of nodes) { if (node.departmentCode === code) { return node; } const found = findDepartment(node.children, code); if (found) return found; } return null; }; return selectedDepartments .map(code => findDepartment(departments, code)) .filter(Boolean) as DepartmentNode[]; }, [departments, selectedDepartments]); // 회사별로 그룹화 const selectedDepartmentsByCompany = React.useMemo(() => { const deptInfo = getSelectedDepartmentInfo(); const grouped = new Map(); deptInfo.forEach(dept => { if (!grouped.has(dept.companyCode)) { grouped.set(dept.companyCode, []); } grouped.get(dept.companyCode)!.push(dept); }); return grouped; }, [getSelectedDepartmentInfo]); // 기존 할당 정보 조회 React.useEffect(() => { if (open && selectedDepartments.length > 0) { const loadExistingAssignments = async () => { setIsLoadingAssignments(true); try { const assignments = await getDepartmentDomainAssignmentsByDepartments(selectedDepartments); setExistingAssignments(assignments as ExistingAssignment[]); } catch (error) { console.error("기존 할당 정보 조회 실패:", error); setExistingAssignments([]); } finally { setIsLoadingAssignments(false); } }; loadExistingAssignments(); } else { setExistingAssignments([]); } }, [open, selectedDepartments]); // 폼 초기화 React.useEffect(() => { if (open) { setSelectedDomain(""); setDescription(""); setIsSubmitting(false); } }, [open]); // 할당 처리 const handleAssign = async () => { if (!selectedDomain || selectedDepartments.length === 0) { return; } setIsSubmitting(true); try { await onAssign({ departmentCodes: selectedDepartments, domain: selectedDomain, description: description.trim() || undefined, }); // 성공 시 다이얼로그 닫기 onOpenChange(false); } catch (error) { console.error("도메인 할당 실패:", error); } finally { setIsSubmitting(false); } }; const canSubmit = selectedDomain && selectedDepartments.length > 0 && !isSubmitting && !isLoading; const selectedDomainInfo = DOMAIN_OPTIONS.find(opt => opt.value === selectedDomain); const hasConflicts = existingAssignments.some(a => a.assignedDomain !== selectedDomain && selectedDomain); return ( 부서별 도메인 할당 선택된 {selectedDepartments.length}개 부서에 도메인을 할당합니다. 상위 부서를 선택한 경우 하위 부서들도 자동으로 포함됩니다.
{/* 선택된 부서들 표시 */}
{Array.from(selectedDepartmentsByCompany.entries()).map(([companyCode, depts]) => (
{companyCode} - {companyInfo.name}
{depts.map((dept) => ( {dept.departmentName || dept.departmentCode} ))}
))}
{/* 기존 할당 현황 */} {(existingAssignments.length > 0 || isLoadingAssignments) && ( <>
{isLoadingAssignments ? (
기존 할당 정보를 조회하는 중...
) : (
부서 현재 도메인 할당일 설명 {existingAssignments.map((assignment) => ( {assignment.departmentName} {getDomainLabel(assignment.assignedDomain)} {new Date(assignment.createdAt).toLocaleDateString('ko-KR')} {assignment.description || '-'} ))}
)} {hasConflicts && (
도메인 변경 주의
일부 부서의 기존 도메인과 다른 도메인을 할당하려고 합니다. 기존 할당은 자동으로 비활성화됩니다.
)}
)} {/* 도메인 선택 */}
{selectedDomainInfo && (
{selectedDomainInfo.label} {selectedDomainInfo.description}
)}
{/* 할당 사유/설명 */}